package com.shj.em.biz.prod.service;

import com.shj.em.base.exception.BizException;
import com.shj.em.base.exception.EmCodeMsg;
import com.shj.em.biz.sell.mapper.OrderMapper;
import com.shj.em.biz.prod.entity.MachineEffort;
import com.shj.em.biz.prod.entity.OrderCnc;
import com.shj.em.biz.prod.mapper.MachineEffortMapper;
import com.shj.em.biz.prod.mapper.OrderCncMapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

import com.shj.em.biz.sys.service.CdService;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;


/**
 * 订单工时表 服务实现类
 *
 * @author Shen Huang Jian
 * @since 2018-11-27
 */
@Service
@Transactional
public class MachineEffortServiceImpl extends ServiceImpl<MachineEffortMapper, MachineEffort> implements MachineEffortService {

    @Autowired
    MachineEffortMapper machineeffortMapper;

    @Autowired
    OrderCncMapper orderCncMapper;

    @Autowired
    OrderMapper orderMapper;

    public List<MachineEffort> findMachineEffortByProgramId(Long programId){
        Map<String, Object> params = new HashMap<>();
        params.put("programId", programId);
        params.put("shiftType", CdService.CD_TYPE_SHIFT);
        return machineeffortMapper.findMachineEffortByProgramId(params);
    }

    public boolean insert(MachineEffort effort){
        validFinishNum(effort.getOrderId(), effort.getProgramId(), effort.getNum(), null);
        adjustEffortHour(effort);
        machineeffortMapper.insert(effort);
        return true;
    }

    private void adjustEffortHour(MachineEffort effort){
        if(!effort.isShiftFlag()){
            effort.setEffortPercent(new BigDecimal(1));
            effort.setShiftFinish(true);
            return;
        }

        if(effort.getNum() == 0){
            // 说明这是未完成的那班, 只能暂时设置一个 effortHour
            OrderCnc cnc = orderCncMapper.selectById(effort.getProgramId());
            int compare = cnc.getProgramHour().compareTo(effort.getWorkHour());
            if(compare < 0){
                //预估时间小于生产时间，用小的时间除以大的时间，得一个估算的比例
                effort.setEffortPercent(cnc.getProgramHour().divide(effort.getWorkHour(), 2, RoundingMode.HALF_UP));

            }else if(compare == 0){
                //预估时间等于生产时间，但是仍然标记未完成，假定一个百分比
                effort.setEffortPercent(new BigDecimal(0.95));
            }else {
                //预估时间小于生产时间，用小的时间除以大的时间，得一个估算的比例
                effort.setEffortPercent(effort.getWorkHour().divide(cnc.getProgramHour(), 2, RoundingMode.HALF_UP));
            }
            effort.setShiftFinish(false);
        }else{
            Map<String, Object> params = new HashMap<>();
            // 说明这个工时是接上一班未完成的那个程序的工时

            // 白班完成的是前一天（碰上周末，不一定是前一天，也许是前几天）夜班的活
            params.put("shift", effort.getShift());
            params.put("workDate", effort.getWorkDt());
            params.put("cncId", effort.getProgramId());
            params.put("machineNo", effort.getMachineNo());
            MachineEffort previous = machineeffortMapper.previousUnFinished(params);
            if(previous == null){
                throw new BizException("未找到交接班时未完成的工件。请确认输入是否正确。");
            }
            //更新上一班的完成比例
            BigDecimal total = previous.getWorkHour().add(effort.getWorkHour());
            previous.setEffortPercent(previous.getWorkHour().divide(total, 2, RoundingMode.HALF_UP));
            previous.setShiftFinish(true);
            machineeffortMapper.updateById(previous);

            effort.setShiftFinish(true);
            effort.setEffortPercent(effort.getWorkHour().divide(total, 2, RoundingMode.HALF_UP));
        }

    }

    public boolean updateById(MachineEffort effort){
        validFinishNum(effort.getOrderId(), effort.getProgramId(), effort.getNum(), effort.getId());
        adjustEffortHour(effort);
        machineeffortMapper.updateById(effort);
        return true;
    }

    public List<MachineEffort> findByDate(Date date){
        return machineeffortMapper.findByDate(date);
    }

    public List<MachineEffort> findWeekEffort(Date weekFrom, Date weekTo){
        return machineeffortMapper.findWeekEffort(weekFrom, weekTo);
    }

    public List<MachineEffort> findWorkDaysInWeek(Date weekFrom, Date weekTo){
        return machineeffortMapper.findWorkDaysInWeek(weekFrom, weekTo);
    }

    private void validFinishNum(Long orderId, Long programId, long num, Long excludeId){
        Map<String, Object> params = new HashMap<>();
        params.put("programId", programId);
        if(excludeId != null){
            params.put("excludeId", excludeId);
        }
        OrderCnc orderCnc = orderCncMapper.selectById(programId);

        BigDecimal finished = machineeffortMapper.queryFinishedNumOfProgram(params);
        boolean isFinished = false;
        if(finished == null){
            if(orderCnc.getTotal() < num){
                throw new BizException(EmCodeMsg.Exceed_Need_Finish);
            }else if(orderCnc.getTotal() == num){
                isFinished = true;
            }
        }else{
            int finish = finished.intValue();
            if(orderCnc.getTotal() < num + finish){
                throw new BizException(EmCodeMsg.Exceed_Need_Finish);
            }else if(orderCnc.getTotal() == num + finish){
                isFinished = true;
            }
        }

        if(isFinished){
            orderCncMapper.updateToFinish(programId);
        }
    }

    public List<MachineEffort> findOneDayMachineEffort(Date today){
        return machineeffortMapper.findOneDayMachineEffort(today);
    }

    public List<MachineEffort> findRangeMachineEffort(Date from, Date to){
        return machineeffortMapper.findRangeMachineEffort(from, to);
    }

    public List<MachineEffort> findMachineUsageDays(Date from, Date to){
        return machineeffortMapper.findMachineUsageDays(from, to);
    }

}
